/*
 * Copyright 2017 Rainbow.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.ghgande.j2mod.modbus.se;

import com.ghgande.j2mod.modbus.net.ModbusTCPListener;
import com.ghgande.j2mod.modbus.net.TCPConnectionHandler;
import com.ghgande.j2mod.modbus.net.TCPSlaveConnection;
import com.ghgande.j2mod.modbus.util.ThreadPool;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author Rainbow
 */
public class SEmodbusTCPListener extends ModbusTCPListener
{
 
    private ServerSocket serverSocket = null;
    private ThreadPool threadPool;
    private Thread listener;
    private boolean useRtuOverTcp;
    private static final Logger logger = LoggerFactory.getLogger(SEmodbusTCPListener.class);
    
    public SEmodbusTCPListener(int poolsize)
    {
        super(poolsize);
    }

    @Override
    public void run()
    {
        try {
            /*
             * A server socket is opened with a connectivity queue of a size
             * specified in int floodProtection. Concurrent login handling under
             * normal circumstances should be alright, denial of service
             * attacks via massive parallel program logins can probably be
             * prevented.
             */
            int floodProtection = 100;
            serverSocket = new ServerSocket(port, floodProtection, address);
            serverSocket.setSoTimeout(timeout);
            logger.debug("Listening to {} (Port {})", serverSocket.toString(), port);
        }

        // Catch any fatal errors and set the listening flag to false to indicate an error
        catch (Exception e) {
            error = String.format("Cannot start TCP listener - %s", e.getMessage());
            listening = false;
            return;
        }

        listener = Thread.currentThread();
        listening = true;
        try {

            // Infinite loop, taking care of resources in case of a lot of
            // parallel logins
            listening = true;
            while (listening) {
                Socket incoming;
                try {
                    incoming = serverSocket.accept();
                }
                catch (SocketTimeoutException e) {
                    continue;
                }
                logger.debug("Making new connection {}", incoming.toString());
                if (listening) {
                    threadPool.execute(new TCPConnectionHandler(this, new SETCPSlaveConnection(incoming, useRtuOverTcp)));
                }
                else {
                    incoming.close();
                }
            }
        }
        catch (IOException e) {
            error = String.format("Problem starting listener - %s", e.getMessage());
        } //To change body of generated methods, choose Tools | Templates.
    }
    
}
